package ua.net.gm.server.world;

import ua.net.gm.common.matter.MatterId;
import ua.net.gm.server.ServerEntitySupport;
import ua.net.gm.server.primitives.Point;
import ua.net.gm.server.primitives.Rectangle;
import ua.net.gm.server.primitives.Size;

/**
 *
 * @author Yason
 */
public class WorldBuilder
{   
    private final ServerEntitySupport entitySupport;
            
    public WorldBuilder(ServerEntitySupport entitySupport)
    {
        this.entitySupport = entitySupport;
    }
    
    public World create(WorldPlan plan)
    {
        checkPlan(plan);
        WorldId id  = entitySupport.getWorldDict().addNextEntity();
        Size size = new Size(plan.getWidth(), plan.getHeight());
        World world = new World(id, size);
        id.setLabel(plan.getLabel());
        
        createBorder(world, plan);
        fillArea(world, plan);
        return world;
    }
    
    private void checkPlan(WorldPlan plan)
    {
        if (plan.getAreaMatter() == null || plan.getAreaMatter().isEmpty())
        {
            throw new IllegalArgumentException("World area matter can't be null or empty");
        }
        if (plan.getHeight() <= 0)
        {
            throw new IllegalArgumentException("World height should be positive but " + plan.getHeight());
        }
        if (plan.getWidth()<= 0)
        {
            throw new IllegalArgumentException("Width width should be positive but " + plan.getWidth());
        }
    }

    private void createBorder(World world, WorldPlan plan)
    {
        if (plan.getBorderMatter() != null)
        {
            MatterId matter = entitySupport.getMatterDict().getId(plan.getBorderMatter());

            // world border field can be single instance I hope
            Field borderField = new Field(matter);
            
            int maxX = world.getSize().getWidth()- 1;
            int maxY = world.getSize().getHeight() - 1;
            
            for (int x = maxX; x >= 0; x--)
            {
                world.setField(x, 0, borderField);
                world.setField(x, maxY, borderField);
            }
            for (int y = maxY; y >= 0; y--)
            {
                world.setField(0, y, borderField);
                world.setField(maxX, y, borderField);
            }
        }
    }

    public static void fillArea(World world, Rectangle r, MatterId matter)
    {
        for (int y = r.getY() + r.getHeight() - 1; y > 0; y--)
        {
            for (int x = r.getX() + r.getWidth() - 1; x > 0; x--)
            {
                world.setField(x, y, new Field(matter));
            }
        }        
    }
    
    private void fillArea(World world, WorldPlan plan)
    {
        int border = plan.getBorderMatter() != null ? 1 : 0;
        Point p = new Point(border, border);
        Size s = new Size(world.getSize().getWidth() - border * 2, world.getSize().getHeight() - border * 2);
        MatterId matter = entitySupport.getMatterDict().getId(plan.getAreaMatter());
        fillArea(world, new Rectangle(p, s), matter);
    }
}
